//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using OpenLS.Spreadsheet.Expressions;
using OpenLS.Spreadsheet.Formats.Biff.Records;
using OpenLS.Spreadsheet.Functions;

namespace OpenLS.Spreadsheet.Formats.Biff.Tokens
{
    internal sealed class AttributeToken : FormulaToken
    {
        private AttributeFlag _flags;
        private ushort _length = 3;
        private ushort _gotoByteOffset;
        private ushort _ignored = ushort.MaxValue;

        public AttributeToken(AttributeFlag flags)
        {
            _flags = flags;
            switch (flags)
            {
                case AttributeFlag.Sum:
                    _ignored = 0;
                    break;
            }
        }

        public AttributeToken()
        {
        }

        public override FormulaTokenId TokenId
        {
            get { return FormulaTokenId.Attr; }
        }

        public override ushort GetLength(FormulaReadContextType formulaReadContextType)
        {
            return _length;
        }

        internal override void ReadContent(FormulaReadContext context)
        {
            ReadReader(context.Reader);
        }
        internal  void ReadReader(BinaryReader reader)
        {
#if DEBUG
            ReadWriteChecker.CheckClass((t, r) => t.ReadReader(r), (t, w) => t.WriteWriter (w), reader, this);
#endif
            var pos = (int)reader.BaseStream.Position;
            _flags = (AttributeFlag)reader.ReadByte();
            switch (_flags)
            {
                case AttributeFlag.None:
                    Debug.WriteLine("problem none token");
                    reader.ReadUInt16();
                    break;
                case AttributeFlag.Volatile:
                    this._ignored = reader.ReadUInt16();
                    break;
                case AttributeFlag.If:
                    _ignored = reader.ReadUInt16();
                    break;
                case AttributeFlag.Goto:
                    _gotoByteOffset = reader.ReadUInt16();
                    break;
                case AttributeFlag.Sum:
                    _ignored = reader.ReadUInt16();
                    break;
                case AttributeFlag.Space:
                    _ignored = reader.ReadUInt16();
                    break;
                case AttributeFlag.Choose:
                    int choiceCount = reader.ReadUInt16();
                    var distances = new List<uint>();
                    for (int i = 0; i < choiceCount; i++)
                    {
                        distances.Add(reader.ReadUInt16());
                    }
                    int last = reader.ReadUInt16();
                    break;
                default:
                    throw new NotImplementedException(_flags.ToString());
            }
            _length = (ushort) ((int) reader.BaseStream.Position - pos);
        }

        public override void WriteContent(FormulaWriteContext context)
        {
            WriteWriter(context.Writer);
        }
        public void WriteWriter (BinaryWriter writer)
        {

            writer.Write((byte) _flags);
            switch (_flags)
            {
                case AttributeFlag.Sum:
                    writer.Write((ushort)_ignored);
                    break;
                case AttributeFlag.If:
                    writer.Write((ushort)_ignored);
                    break;
                case AttributeFlag.Space:
                    writer.Write(_ignored);
                    break;
                case AttributeFlag.Goto:
                    writer.Write((ushort)_gotoByteOffset);

                    break;
                case AttributeFlag.Volatile:
                    writer.Write((ushort)_ignored);
                    break;

                case AttributeFlag.Assign:
                case AttributeFlag.Choose:
                case AttributeFlag.None:
//\\                case AttributeFlag.Goto:
                case AttributeFlag.SpaceVolatile:
               // case AttributeFlag.Volatile:
                    throw new NotImplementedException(_flags.ToString());
                default:
                    throw new NotSupportedException();
            }
        }

        internal override Expression GetExpression(FormulaEvaluationContext context)
        {
            switch (_flags)
            {
                case AttributeFlag.None:
                    {
                        Debug.WriteLine("problem none token");
                        return context.PoppedArgument().GetExpression(context);
                    }
                case AttributeFlag.Space:
                    {
                        if (context.Arguments.Count == 0)
                            return null;
                        FormulaToken previous = context.PoppedArgument();
                        return previous.GetExpression(context);
                    }
                case AttributeFlag.Goto:
                    return context.PoppedArgument().GetExpression(context);
                case AttributeFlag.If:
                    return context.PoppedArgument().GetExpression(context);
                case AttributeFlag.Choose:
                    return context.PoppedArgument().GetExpression(context);
                case AttributeFlag.Sum:
                    {
                        FormulaToken previous = context.PoppedArgument();
                        Expression other = previous.GetExpression(context);
                        Function f = context.Workbook.Document.Context.GetFunction("SUM", false);
                        return new FunctionInvokeExpression(f,
                                                            new List<Expression>
                                                                {
                                                                    other
                                                                }
                                                            ,
                                                            context.Workbook.Document.Context)
                            ;
                    }

                default:
                    throw new NotImplementedException(_flags.ToString());
            }
        }
    }
}